import { BoundingSphere, Cartesian3, Ellipsoid, Math as CesiumMath, Matrix3, Matrix4, Quaternion, Cartesian2, Ray, IntersectionTests, Cartographic, Rectangle } from 'cesium'
import PerspectiveFrustum from './Frustum ';
import Scene from './Scene';
export default class Camera {
    _position: Cartesian3;
    _direction: Cartesian3;
    _up: Cartesian3;
    frustum: PerspectiveFrustum;
    _viewMatrix: Matrix4;
    _scene: Scene;
    private _right: Cartesian3;
    initDistance: number;
    /**
     * @description: 不传值构造函数，就是默认值
     */
    constructor(scene: Scene) {
        this._position = new Cartesian3(0, 20000000, 0);
        this._direction = new Cartesian3(0, -1, 0);
        this._up = new Cartesian3(0, 0, 1);
        this._scene = scene;
        this.frustum = new PerspectiveFrustum();
        this._right = Cartesian3.cross(this._direction, this._up, new Cartesian3());
        this._right = Cartesian3.normalize(this._right, this._right); // 归一化
        this._viewMatrix = new Matrix4();
        let sphere = new BoundingSphere(Cartesian3.ZERO, 6378137)
        this.initDistance = this.distanceToBoundingSphere(sphere);
    }

    public get ViewMatrix(): Matrix4 {
        this._viewMatrix = new Matrix4();
        Matrix4.computeView(this._position, this._direction, this._up, this._right, this._viewMatrix);
        return this._viewMatrix;
    }
    public computeViewRectangle() {
        //判断剔除体是否和椭球体包围球相交
        let leftTopCorner = new Cartesian2(0, 0);
        let rightTopCorner = new Cartesian2(0, this._scene.canvas.width);
        let rightBottomCorner = new Cartesian2(this._scene.canvas.height, 0);
        let leftBottomCorner = new Cartesian2(this._scene.canvas.width, this._scene.canvas.height);
        let leftTopIntersection = this.pickEllipsoid(leftTopCorner, Ellipsoid.WGS84);
        if (leftTopIntersection) {
            let rightTopIntersection = this.pickEllipsoid(rightTopCorner, Ellipsoid.WGS84);
            let rightBottomIntersection = this.pickEllipsoid(rightBottomCorner, Ellipsoid.WGS84);
            let leftBottomIntersection = this.pickEllipsoid(leftBottomCorner, Ellipsoid.WGS84);
            return Rectangle.fromCartesianArray([leftTopIntersection, rightTopIntersection, rightBottomIntersection, leftBottomIntersection])
        }
        return null
        // let rectangle=Rectangle.fromCartesianArray()

    }
    /**
     * move,让相机往各个方向移动，笛卡尔坐标
     */
    moveForward(distance: number) {
        // 获取相机的当前前向量
        const forward = new Cartesian3();
        Cartesian3.normalize(this._direction, forward);

        // 计算前进方向的新位置
        const moveAmount = new Cartesian3();
        Cartesian3.multiplyByScalar(forward, distance, moveAmount);
        Cartesian3.add(this._position, moveAmount, this._position);
        // this.computeViewRectangle();
    }
    /**
     *此处旋转的思路是先绕地球z轴旋转，再绕地球子午面的切向量（相机右向量）旋转，
     改变相机的位置，同时调整相机的方向
     */
    public rotate(anglex: number, angley: number, anglez: number) {
        // 定义旋转轴，这里以Z轴为例,相机层我们仍然使用笛卡尔坐标系
        const rotationAxisZ = Cartesian3.UNIT_Z;
        //该矩阵表示绕地球Z轴旋转
        const quaternionZ = Quaternion.fromAxisAngle(rotationAxisZ, anglez);
        // 创建旋转矩阵,改变相机的位置
        const rotationMatrixZ = Matrix3.fromQuaternion(quaternionZ);
        Matrix3.multiplyByVector(rotationMatrixZ, this._position, this._position);
        Matrix3.multiplyByVector(rotationMatrixZ, this._up, this._up);
        Matrix3.multiplyByVector(rotationMatrixZ, this._direction, this._direction);

        //算的相机的右向量也是第二部旋转的旋转轴，即相机此时对应子午面的切向量
        Cartesian3.cross(this._direction, this._up, this._right);
        const quaternionRight = Quaternion.fromAxisAngle(this._right, anglex); //该矩阵表示绕相机右向量旋转
        const rotationMatrixRight = Matrix3.fromQuaternion(quaternionRight);
        Matrix3.multiplyByVector(rotationMatrixRight, this._position, this._position);
        Matrix3.multiplyByVector(rotationMatrixRight, this._up, this._up);
        Matrix3.multiplyByVector(rotationMatrixRight, this._direction, this._direction);
        // this._right = Cartesian3.cross(this._direction, this._up, new Cartesian3());
        this._right = Cartesian3.normalize(this._right, this._right); // 归一化
    }
    /**
     * @description: 计算相机和包围球相交的距离
     */

    distanceToBoundingSphere(boundingSphere: BoundingSphere) {
        const sphereCenter = boundingSphere.center;
        const distanceToCenter = Cartesian3.distance(this._position, sphereCenter);
        const distanceToFront = Math.max(0, distanceToCenter - boundingSphere.radius);
        return distanceToFront;
    }

    distanceToPoint(point: Cartesian3) {
        const distance = Cartesian3.distance(this._position, point);
        return distance;
    }

    pickEllipsoid(windowPosition: Cartesian2, ellipsoid?: Ellipsoid): Cartesian3 | undefined {
        const width = this._scene.canvas.width;
        const height = this._scene.canvas.height;
        const tanPhi = Math.tan(this.frustum.fovy * 0.5);
        const tanTheta = this.frustum.aspectRatio * tanPhi;
        const near = this.frustum.near;
        const x = (2.0 / width) * windowPosition.x - 1.0;
        const y = (2.0 / height) * (height - windowPosition.y) - 1.0;
        const nearCenter = Cartesian3.multiplyByScalar(
            this._direction,
            near,
            new Cartesian3()
        );
        Cartesian3.add(this._position, nearCenter, nearCenter);
        const xDir = Cartesian3.multiplyByScalar(
            this._right,
            x * near * tanTheta,
            new Cartesian3()
        );
        const yDir = Cartesian3.multiplyByScalar(
            this._up,
            y * near * tanPhi,
            new Cartesian3()
        );
        const direction = Cartesian3.add(nearCenter, xDir, new Cartesian3());
        Cartesian3.add(direction, yDir, direction);
        Cartesian3.subtract(direction, this._position, direction);
        Cartesian3.normalize(direction, direction);
        const ray = new Ray(this._position, direction);
        let intersection = IntersectionTests.rayEllipsoid(ray, ellipsoid);
        if (intersection) {
            const entryPoint = Ray.getPoint(ray, intersection.start);
            return entryPoint;
        }
        return undefined;
    }

}
